home *** CD-ROM | disk | FTP | other *** search
- /* $VER: pasm support.c V0.5 (12.10.97)
- *
- * This file is part of pasm, a portable PowerPC assembler.
- * Copyright (c) 1997 Frank Wille
- *
- * pasm is freeware and part of the portable and retargetable ANSI C
- * compiler vbcc, copyright (c) 1995-97 by Volker Barthelmann.
- * pasm may be freely redistributed as long as no modifications are
- * made and nothing is charged for it. Non-commercial usage is allowed
- * without any restrictions.
- * EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
- * SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
- *
- *
- * v0.5 (12.10.97) phx
- * lower_case(), converts a whole string to lower case.
- * try_mapfile() adds a '\n'-byte to every file it reads.
- * v0.4 (28.06.97) phx
- * remnode(), removes a node from a list.
- * mapfile() automatically adds '/' to an include path.
- * v0.3 (26.03.97)
- * Little to big endian conversion routine - l2bh(), l2bw().
- * v0.2 (25.03.97) phx
- * Writes ELF object for 32-bit PowerPC big-endian. Either absolute
- * or ELF output format may be selected. ELF is default for all
- * currently supported platforms. PPCasm supports nine different
- * relocation types (there are much more...).
- * Compiles and works also under NetBSD/amiga (68k).
- * Changed function declaration to 'new style' in all sources
- * (to avoid problems with '...' for example).
- * checkrange() prints a warning message on overflow and no error.
- * remhead() returns NULL when list is empty.
- * v0.1 (11.03.97) phx
- * First test version with all PowerPC instructions and most
- * important directives. Only raw, absolute output.
- * checkrange() size 3 checks for 26-bit values instead 24-bit.
- * Do we need a special allocation routine for strings?
- * v0.0 (15.02.97) phx
- * File created.
- */
-
-
- #define SUPPORT_C
- #include "ppcasm.h"
-
-
- void *alloc(size_t);
- void *alloczero(size_t);
- char *allocstring(char *);
- void initlist(struct list *);
- void addtail(struct list *,struct node *);
- struct node *remhead(struct list *);
- char *mapfile(struct GlobalVars *,char *);
- void checkrange(uint32,int,bool);
- #ifdef LITTLEENDIAN
- uint16 l2bh(uint16);
- uint32 l2bw(uint32);
- #endif
-
- static char *try_mapfile(char *);
- static size_t filesize(FILE *,char *);
-
-
-
- void *alloc(size_t size)
- /* allocate memory and print error message if not enough available */
- {
- void *p;
-
- if (!size)
- size = 1;
- if (!(p = malloc(size)))
- error(1); /* out of memory */
- return (p);
- }
-
-
- void *alloczero(size_t size)
- /* same as alloc() but zeroes the allocated memory */
- {
- void *p = alloc(size);
-
- memset(p,0,size);
- return (p);
- }
-
-
- char *allocstring(char *s)
- /* allocate space for a single string */
- /* @@@ this should be improved by some kind of string buffer */
- {
- char *p = alloc(strlen(s)+1);
-
- strcpy(p,s);
- return (p);
- }
-
-
- void initlist(struct list *l)
- /* initializes a list structure */
- {
- l->first = (struct node *)&l->dummy;
- l->dummy = NULL;
- l->last = (struct node *)&l->first;
- }
-
-
- void addtail(struct list *l,struct node *n)
- /* add node as last element of list */
- {
- struct node *ln = l->last;
-
- n->next = ln->next;
- ln->next = n;
- n->pred = ln;
- l->last = n;
- }
-
-
- struct node *remhead(struct list *l)
- /* remove first node in list and return a pointer to it */
- {
- struct node *n = l->first;
-
- if (n->next) {
- l->first = n->next;
- n->next->pred = n->pred;
- return (n);
- }
- return (NULL);
- }
-
-
- struct node *remnode(struct node *n)
- /* remove a node from a list */
- {
- n->next->pred = n->pred;
- n->pred->next = n->next;
- return (n);
- }
-
-
- char *mapfile(struct GlobalVars *gv,char *name)
- /* map a complete file into memory and return its address */
- /* the file's length is returned in *(p-sizeof(size_t)) */
- /* all defined paths will be searched for the file, before aborting */
- {
- char *p;
- int i;
- size_t l;
- char full_name[FNAMEBUFSIZE];
-
- if (p = try_mapfile(name))
- return (p);
- for (i=0; i<MAX_INCPATHS; i++) {
- if (gv->incpaths[i]) {
- strncpy(full_name,gv->incpaths[i],FNAMEBUFSIZE-1);
- l = strlen(gv->incpaths[i]);
- if (l < (FNAMEBUFSIZE-2)) {
- if (full_name[l-1]!='/' && full_name[l-1]!=':')
- full_name[l++] = '/';
- strncat(full_name,name,(FNAMEBUFSIZE-1)-l);
- if (p = try_mapfile(full_name))
- return (p);
- }
- }
- }
- error(6,name); /* can't open file */
- }
-
-
- static char *try_mapfile(char *name)
- {
- FILE *fp;
- char *p=NULL;
- size_t fsiz;
-
- if (fp = fopen(name,"r")) {
- fsiz = filesize(fp,name);
- p = alloc(fsiz+1+sizeof(size_t));
- *(size_t *)p = fsiz + 1; /* store file size before the text starts */
- p += sizeof(size_t);
- if (fread(p,1,fsiz,fp) != fsiz) {
- fclose(fp);
- error(5,name); /* read error */
- }
- fclose(fp);
- *(p+fsiz) = '\n'; /* always have a '\n'-byte at the end */
- }
- return (p);
- }
-
-
- static size_t filesize(FILE *fp,char *name)
- {
- /* somebody knows a better way to determine file size in ANSI C? */
- long oldpos,size;
-
- if ((oldpos = ftell(fp)) >= 0)
- if (fseek(fp,0,SEEK_END) >= 0)
- if ((size = ftell(fp)) >= 0)
- if (fseek(fp,oldpos,SEEK_SET) >= 0)
- return ((size_t)size);
- fclose(fp);
- error(5,name); /* read error - doesn't return */
- }
-
-
- void checkrange(uint32 val,int size,bool sign)
- /* checks if an integer value is in range, size=3 means 26-bit (B-instr.) */
- {
- int sval;
-
- if (sign) {
- sval = (int)val;
- switch (size) {
- case 1:
- if (sval>0x7f || sval<-0x80)
- error(30,8); /* immediate operand doesn't fit into 8 bits */
- break;
- case 2:
- if (sval>0x7fff || sval<-0x8000)
- error(30,16);
- break;
- case 3:
- if (sval>0x1ffffff || sval<-0x2000000)
- error(30,24);
- break;
- }
- }
- else {
- switch (size) {
- case 1:
- if (val>0xff)
- error(30,8);
- break;
- case 2:
- if (val>0xffff)
- error(30,16);
- break;
- case 3:
- if (val>0x3ffffff)
- error(30,24);
- break;
- }
- }
- }
-
-
- void lower_case(char *s)
- /* convert a whole string to lower case */
- {
- unsigned char c;
-
- while (c = (unsigned char)*s)
- *s++ = tolower((int)c);
- }
-
-
- #ifdef LITTLEENDIAN
- uint16 l2bh(uint16 x)
- /* little endian half word conversion */
- {
- return ECH(x);
- }
-
-
- uint32 l2bw(uint32 x)
- /* little endian word conversion */
- {
- return ECW(x);
- }
- #endif
-